home *** CD-ROM | disk | FTP | other *** search
- Path: solon.com!not-for-mail
- From: seebs@solutions.solon.com (Peter Seebach)
- Newsgroups: comp.lang.c
- Subject: Re: Schildt <- Advanced Books
- Date: 11 Feb 1996 11:23:45 -0600
- Organization: Usenet Fact Police (Undercover)
- Message-ID: <4fl8n1$n2@solutions.solon.com>
- References: <8BA8405.02C70020DE.uuout@sourcebbs.com>
- NNTP-Posting-Host: solutions.solon.com
-
- In article <8BA8405.02C70020DE.uuout@sourcebbs.com>,
- DAVID MOHORN <david.mohorn@sourcebbs.com> wrote:
- >The only book that I know of that uses the notorious void main(void) is
- >his "Teach Yourself C" book. But he only uses this for the first half
- >of the book. This is only because he doesn't want the reader to be
- >overwhelmed with all the data types and other things until he has a
- >chance to explain how functions return values and pass arguments.
-
- How about "C: The Complete Reference" - *the entire book*.
-
- Everywhere in it, and he even claims that it's legal (page 163, in the
- 3rd edition.)
-
- [Re: C: TCR]
-
- >I think it is a great reference!!! Now if Schildt will just write a
- >"Teach Yourself Assembler" book that blows Mark Goodwin's book away.
- >This book really stunk. It was nothing more than the User Guide that
- >comes with the Assembler. YUCK!
-
- I think it is a horrid reference. It makes *many* mistakes, several of
- them stupid. I'll append my (incomplete) list. Look through this list,
- and try to tell me *none* of these are a problem in a reference manual.
- I think all of them are at least moderately bad.
-
- >M>Born To Code In C develops a multi-threaded program! That's
- > >as advanced as you can get. In DOS, way before multi-threaded OSes
- > >like NT and OSF/1 came out.
-
- >I agree.
-
- Nothing advanced about it; I wrote multithreaded programs before I knew what
- they were. He doesn't *understand* advanced topics; he programs by luck
- and cut-n-paste, without understanding why things work. (You can tell; if
- he understood, he'd explain them correctly, rather than making
- curious but irrelevant statements.)
-
- >This would be great. I see his "Teach Yourself C" is not in its 2nd
- >Edition.
-
- Yup. And the third edition managed to correct typos without correcting
- errors. The most visibly *stupid*, imho, is the one on page 53 (see
- included text) having to do with sizeof. It's never been right, I have
- never even *heard* of a machine where it could be right, and he even
- contradicts it later on. (Correctly so, I might add.)
-
- [Begin included text.]
- I am not including "bad style", but there are a few of those (gets is
- strongly depracated, and many programs don't output the last newline,
- probably because MS-DOS prints an extra one before the prompt.)
-
- Please pardon typos, and even the possible errors; I have not taken the time
- to verify a couple of things. For a serious, aimed-at-publication effort,
- I would, of course, take the time to bring the questionable points to the
- attention of people in comp.std.c, or otherwise cross-reference the work.
- As is, I'm just using memory and the Standard to compare.
-
- Flat contradictions of ANSI's standard.
-
- Page 163
-
- "You may also declare main() as void if it does
- not return a value."
-
- Specifically untrue. ANSI mandates two declarations for main, and
- says that main may have declarations compatible with those. Both
- return int.
-
- Page 434
-
- "free() must only be called with a pointer that was
- previously allocated with one of the dynamic allocation
- system's functions (either malloc(), realloc(), or
- calloc())."
-
- Also specifically untrue. ANSI states that free(NULL) is legal and
- has no effect. (Also note that it must be called with a pointer
- *to space previously allocated*, not with a pointer previously
- allocated, and that the pointer must not have been already freed
- or passed to realloc().)
-
- Page 314
-
- "However, since EOF is a valid integer value, you must use
- feof() to check for end-of-file when working with binary
- files."
-
- Not merely a little bit untrue, but utterly wrong, and specifically
- missing the point of the rule (correctly stated) about returning
- the char as "unsigned char converted to int" (actually stated
- in the standard in 7.9.7.1, under fgetc()).
-
- Since EOF is a *NEGATIVE* integral constant, it can *NEVER* compare
- equal to *ANY* unsigned char. When you are reading from a binary
- file, the values you get will *never* compare equal to EOF, until
- getchar() returns EOF because the file is empty.
-
- This correlates with a mistake made in all of the examples where
- loops break on '$', 'A', or ' ' because the return from getchar() is
- immediately put into a char variable.
-
- This is a more serious flaw than many, because it results in poorly
- written, inefficient code.
-
- (Couple this with the consistent attempts to use feof() to see if
- the *next* read will fail, when in fact feof() only returns true
- when the *PREVIOUS* read failed, and you get a completely wrong
- description of the standard I/O library.)
-
- Also, several of the programs given loop forever if an end of
- file is reached, because EOF is not checked for in a loop.
-
- (The astute reader will note that he is correct for implementations
- in which char and int are the same size; I disregard this because:
- 1. This violates the spirit, if not the letter, of the
- standard.
- 2. The implementation he is discussing does not have this
- problem.
- In such an environment, the "correct" thing to do is probably to
- use fread and check for failure. feof() will still not warn you that
- your next read will fail.)
-
- Page 284
-
- All of the header files are listed in capitals; the standard
- specifies them in lower case. It is not required that a
- C compiler reject all-caps, but nor is it required that it
- accept them.
-
- Flat contradictions of POSIX, in the discussion of open/read/write.
-
- Page 253
-
- "In most implementations, the operation fails if the file
- specified in the open statement does not exist on the disk."
-
- To the best of my knowledge, POSIX (the standard for the open()
- call) documents and requires the functionality of the O_CREAT flag.
-
- Undefined behavior/illegal code.
-
- Page 247
-
- The stream fp is opened with mode "r", the mode to open a text file.
- Then, fseek is called on fp, with the 2nd argument not a value
- returned by a previous call to ftell. (ANSI 7.9.9.2, "For a text
- stream, either offset shall be zero, or offset shall be a value
- returned by an earlier call to the ftell function on the same stream
- and whence shall be SEEK_SET.")
-
- Page 63
-
- If scanf fails, the variable guess is referenced before it has been
- initialized; accessing an uninitialized object introduces
- undefined behavior.
-
- Page 283
-
- >#include <string.h>
- >
- >char s1[] = "hello ";
- >char s2[] = "there.";
- >
- >void main(void)
- >{
- > int p;
- >
- > p = strcat(s1, s2);
- >}
-
- It is correctly noted that this generates a warning. Not mentioned
- is that it's illegal; although s1[] is a modifiable array, it is
- an array large enough to hold "hello " (and the terminating NUL),
- so it has room for 7 bytes. The strcat overflows the array, producing
- undefined behavior.
-
- Page 735
-
- This is spectacularly wrong; the "corrected"
-
- "x = *p * (*p++);"
-
- is *EXACTLY* equivalent in terms of C; as correctly noted earlier,
- the order of evaluation *IS NOT SPECIFIED*.
-
- The code is still illegal (p is used to determine *p on the left
- of the *, as well as modified on the right), and the parentheses
- aren't affecting the code at all.
-
- In this code, p can be incremented anywhere in the line; the only
- requirement would be that the value of (*p++) be the same as
- the value of (*p) before the increment. It is *not* specified
- whether the other *p happens before or after the increment.
-
- In fact, because the code modifies an object (p) and uses the value
- of the object to do something other than determine the new value
- (The first "*p"), it is *illegal*. Completely; a compiler is allowed
- to reject the code, and many will produce surprising results from
- this operation.
-
- This is not merely wrong, it's wrong *while discussing the problem*,
- which is doubly bad.
-
- Code which does not do what it says it does.
-
- Page 333
-
- After
-
- >char str[80];
- >
- >sprintf(str,"%s %d %c", "one", 2, 3);
-
- it is asserted that str will contain "one 2 3". This is incorrect;
- it would contain "one 2 ^C".
-
- Page 53
-
- >printf("%f", sizeof f);
-
- Clearly wrong; sizeof is not a double or float.
-
- Page 53
-
- >printf("%d", sizeof(int));
-
- Subtly wrong; sizeof is a size_t, which may not be any sort of int.
- The only safe way to do this is
-
- >printf("%lu", (unsigned long) sizeof(int));
-
- While this is larger, a clear explanation of why it is required will
- go a long way towards helping people understand C.
-
- Page 53 (This one's popular)
-
- >/* Write 6 integers to a disk file. */
- >void put_rec(int rec[6], FILE *fp)
- >{
- > int len;
- >
- > len = fwrite(rec, sizeof rec, 1, fp);
- > if (len != 1) printf("write error");
- >}
-
- Incorrect. As correctly noted elsewhere, when "int rec[6]" is an
- argument to a function, it actually specifies a pointer-to-int,
- not an array[6]-of-int. sizeof rec is sizeof(int *) here, and this
- code works only if sizeof(int *) is precisely 6 times sizeof(int).
- (Not impossible, but hardly likely.)
-
- Further, who said fp was a disk file? fp could be stdout.
-
- Inaccurate or misleading explanations.
-
- Page 132
-
- "After the assignment, p points to the first 1000 bytes of
- free memory."
-
- No, p points to at least 1000 bytes of allocated space, which is
- not free memory. There is also no reason to assume it was the
- "first" 1000 bytes; top-down allocation is not atypical, and
- further, there's no reason to assume this code fragment runs in
- isolation.
-
- Page 197
-
- It is redundant to give a size of char in bytes as 1 as an
- "assumption" - it's the definition, sizeof() gives the size
- in *chars*.
-
- Page 162
-
- Functions are not of type void; functions are of various types,
- called collectively the function types. A function may have a
- return of type void, which means that its type is something like
- "function taking (...) and returning void".
-
- Page 59
-
- "This shorthand works for all the binary operators..."
-
- No, it doesn't. It doesn't work for ".", "->", "&&", or "||".
-
- Page 33
-
- "static Global Variables" [heading]
-
- No such thing. A static variable outside of a function has file
- scope, which is distinct from global scope.
-
- Explanations of a DOS-specific feature as "how C works".
-
- Page 19
-
- "In general, negative numbers are represented using the
- two's complement approach..."
-
- This is not a C feature. It is a common implementation, but it is
- specifically not required.
-
- Page 131
-
- "Memory allocated by C's dynamic allocation functions is
- obtained from the <i>heap</i> -- the region of free memory
- that lies between your program and its permanent storage
- area and the stack."
-
- C does not specify that there is a stack - only that functions can
- call each other. The "heap" is a DOS term, and the layout is not
- a part of the C language. It is not atypical for the layout to be
- radically different, and certainly, there is no call for describing
- a specific choice as "what happens".
- --
- Peter Seebach - seebs@solon.com - Copyright 1995 Peter Seebach.
- C/Unix wizard -- C/Unix questions? Send mail for help. No, really!
- FUCK the communications decency act. Goddamned government. [literally.]
- The *other* C FAQ - ftp taniemarie.solon.com /pub/c/afq - Not A Flying Toy
-